/**
 * Copyright (c) 2023 murenchao
 * taomu is licensed under Mulan PubL v2.
 * You can use this software according to the terms and conditions of the Mulan PubL v2.
 * You may obtain a copy of Mulan PubL v2 at:
 *       http://license.coscl.org.cn/MulanPubL-2.0
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PubL v2 for more details.
 */
package cool.taomu.utils

import java.io.File
import java.io.IOException
import java.io.RandomAccessFile
import java.nio.ByteBuffer
import java.nio.MappedByteBuffer
import java.nio.channels.FileChannel
import java.nio.channels.FileLock

class ShareMemory implements AutoCloseable {
	int shareMemorySzie = 41779264;
	int fileSize = 0;
	MappedByteBuffer mmap = null;
	FileChannel fcl = null;
	RandomAccessFile raf = null;

	new(String file) {
		this.filename = file;
	}

	new() {
	}

	def synchronized write(int start, int size, byte[] buffer) {
		if (start >= fileSize || start + size >= fileSize) {
			return 0;
		}
		var FileLock flock = null;
		try {
			flock = fcl.lock(start, size, false);
			if (flock !== null) {
				mmap.position(start);
				mmap.put(ByteBuffer.wrap(buffer));
				flock.release();
				return size;
			}
		} catch (IOException ex) {
			if (flock !== null) {
				flock.release;
			}
		}
		return 0;
	}

	def synchronized read(int start, int size, byte[] buffer) {
		if (start >= fileSize) {
			return 0;
		}
		var FileLock flock = null;
		var _size = size;
		try {
			flock = fcl.lock(start, size, false);
			if (flock !== null) {
				mmap.position(start);
				if (mmap.remaining < size) {
					_size = mmap.remaining;
				}
				if (_size > 0) {
					mmap.get(buffer, 0, _size);
				}
				flock.release;
				return _size;
			}
		} catch (Exception e) {
			if (flock !== null) {
				flock.release
			}
		}
		return 0;
	}

	override close() throws Exception {
		if (fcl !== null) {
			fcl.close;
		}
		if (raf !== null) {
			raf.close;
		}
		mmap = null;
	}

	def static void main(String[] args) {
		var ShareMemory sm = new ShareMemory("/home/rcmu/a.txt");
		var a = "Hello World!!!!";
		sm.write(1, 20, a.bytes);
		var b = newByteArrayOfSize(20);
		sm.read(1, 20, b);
		System.out.println(new String(b, "UTF-8"));
	}

	def setFilename(String filename) {
		setFilename(new File(filename))
	}

	def setFilename(File file) {
		try {
			raf = new RandomAccessFile(file, "rw");
			fcl = raf.channel;
			fileSize = fcl.size as int;
			if (fileSize < shareMemorySzie) {
				var bb = ByteBuffer.wrap(newByteArrayOfSize((shareMemorySzie - fileSize) as int));
				bb.clear;
				fcl.position(fileSize);
				fcl.write(bb);
				fcl.force(false);
				fileSize = shareMemorySzie;
			}
			mmap = fcl.map(FileChannel.MapMode.READ_WRITE, 0, fileSize);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

}
